﻿using Microsoft.SharePoint.Administration;
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using CNRS.CCP.Config;
using CNRS.CCP.DAO;

namespace CNRS.CCP.Connector
{
	/// <summary>
	/// Handles all LDAP related action
	/// </summary>
	class LdapConnector
	{

		/// <summary>
		/// Find by email address 
		/// </summary>
		/// <param name="partialEmailAddress"></param>
		/// <returns></returns>
		public static List<DataElement> GetDataElements(string partialEmailAddress)
		{
			LogHelper.LogDebug(LogCategorie.LdapHelper, string.Format("Arg 'partialEmailAddress' -> '{0}'", partialEmailAddress));

			try
			{
				//List of prohibided characters
				char[] prohibidedCharArray = { '&', '=', '!', '(', ')', '~', '|' };

				//List of result
				List<DataElement> dataElements = null;
				List<string> eMailsResults = new List<string>();

				if (!partialEmailAddress.Contains('@')
					|| (partialEmailAddress.IndexOfAny(prohibidedCharArray) != -1)
					|| (partialEmailAddress.Count(elt => elt == '*') > 3)
				)
				{
					return dataElements;
				}

				// get LDAP parameters
				Provider userProvider = ClaimsParameters.Instance.UserProvider;
				UserElement userElement = ClaimsParameters.Instance.UserElements[0];

				string[] serverString = userProvider.Server.Split('|');

				//string encryptedData = userProvider.Password;
				//SecureString password = SecurityHelper.DecryptString(encryptedData);

				// define the root of your search - by default, the top-level of your domain
				using (DirectoryEntry rootEntry = new DirectoryEntry(serverString[0], userProvider.User, userProvider.Password, System.DirectoryServices.AuthenticationTypes.ServerBind))
				{
					if (serverString.Length > 1 && serverString[1].ToLower() == "ssl")
					{
						rootEntry.AuthenticationType = System.DirectoryServices.AuthenticationTypes.SecureSocketsLayer;
					}
					// define a searcher
					DirectorySearcher searcher = new DirectorySearcher(rootEntry);

					// set the filter for the searcher - the LDAP filter syntax is a bit
					// odd at times; for details see  
					// http://msdn2.microsoft.com/en-us/library/aa746475.aspx
					// http://www.selfadsi.org/ldapfilter.htm
					searcher.Filter = string.Format(userElement.Query, partialEmailAddress);

					// define the properties you want in the search results
					searcher.PropertiesToLoad.Add(userElement.Value);
					searcher.PropertiesToLoad.Add(userElement.Display);
					searcher.PropertiesToLoad.Add(userElement.Email);

					// search scope - here: search the whole subtree below your root
					searcher.SearchScope = SearchScope.Subtree;

					//on SP 2013 and openLdap, it seems that this sort option does not work anymore
					//just keep the code in case we try to put it back with 2013 people picker
					// define the sort order for the results
					//searcher.Sort = new SortOption("sn", SortDirection.Ascending);

					// find the results
					SearchResultCollection results = searcher.FindAll();

					if (results != null)
					{
						dataElements = new List<DataElement>();

						// iterate through the results
						foreach (SearchResult result in results)
						{
							// extract the resulting values - be careful: if a property has no value
							// associated with it, (result.Properties[....]) will be null! Check for that!
							// Also - a property can contain more than one result value - but make sure
							// there's at least one! If there's more than one, you might need to write
							// some additional code to deal with that...
							string mail = string.Empty;
							if (result.Properties[userElement.Email] != null && result.Properties[userElement.Email].Count > 0)
							{
								mail = result.Properties[userElement.Email][0].ToString();
							}

							string displayValue = string.Empty;
							if (result.Properties[userElement.Display] != null && result.Properties[userElement.Display].Count > 0)
							{
								if (result.Properties[userElement.Display][0].GetType().Name == "Byte[]")
								{
									Byte[] tmp = (Byte[]) result.Properties[userElement.Display][0];
									displayValue = Encoding.UTF8.GetString(tmp);
								}
								else
								{
									displayValue = result.Properties[userElement.Display][0].ToString();
								}
							}

							// output your result(s)
							LogHelper.LogDebug(LogCategorie.LdapHelper, string.Format("Mail found : '{0}'", mail));
							DataElement dataElement = new DataElement();
							dataElement.Value = mail;
							dataElement.Display = displayValue;
							dataElement.Email = mail;

							dataElements.Add(dataElement);
						}
					}
				}

				return dataElements;
			}
			catch (Exception ex)
			{
				LogHelper.Log(LogCategorie.LdapHelper, "error : " + ex, TraceSeverity.Unexpected);
				return null;
			}
		}

	}
}
